using System;
using System.Collections.Generic;
using System.Text;
using OpenTK.Math;
using System.Text.RegularExpressions;
using System.Drawing;
using System.Globalization;

namespace Dogfight2008.Common
{
  public class CplLoader
  {
    public static ColoredPolygonMesh FromString()
    {
      return new ColoredPolygonMesh(new List<ColoredPolygon>());
    }

    public static ColoredPolygonMesh FromString(string repr)
    {
      List<string> lines = new List<string>(Q.Lines(repr));
      // 0:cpl
      // 1:vertices #
      // 2:polygons #
      // 3:---8<---
      if (lines.Count < 4)
        throw new Exception("Syntax error, cpl files are at least 4 lines long");
      if (lines[0].ToLower() != "cpl")
        throw new Exception("Expected cpl, found " + lines[0]);
      if (lines[3] != "---8<---")
        throw new Exception("Expected end-of-header ---8<---, found " + lines[3]);
      int vertices = ParseNumVertices(lines[1]);
      int polygons = ParseNumPolygons(lines[2]);

      string rest = Q.Split(repr, "---8<---")[1];

      return CreateMesh(vertices, polygons, rest);
    }

    private static ColoredPolygonMesh CreateMesh(int numvertices, int numpolygons, string rest)
    {
      FixedList<string> rows = new FixedList<string>(Q.Lines(rest));
      FixedList<string> vertexData = rows.Sublist(1, numvertices);
      FixedList<string> polyData = rows.Sublist(numvertices + 1, numpolygons);
      FixedList<Vector3> vertices = ParseVertices(vertexData);
      FixedList<ColoredPolygon> polys = ParsePolygons(polyData, vertices);

      return new ColoredPolygonMesh(polys);
    }

    private static FixedList<ColoredPolygon> ParsePolygons(FixedList<string> polyData, FixedList<Vector3> vertices)
    {
      List<ColoredPolygon> polys = new List<ColoredPolygon>();
      foreach (string row in polyData)
      {
        string[] words = Q.Words(row);
        int numIndices = int.Parse(words[0]);
        int r = int.Parse(words[1]);
        int g = int.Parse(words[2]);
        int b = int.Parse(words[3]);
        List<Vector3> vertexData = new List<Vector3>();
        for (int i = 0; i < numIndices; i++)
          vertexData.Add(vertices[int.Parse(words[4 + i])]);
        polys.Add(new ColoredPolygon(Color.FromArgb(r, g, b), vertexData));
      }
      return new FixedList<ColoredPolygon>(polys);
    }

    private static FixedList<Vector3> ParseVertices(FixedList<string> vertexData)
    {
      List<Vector3> vertices = new List<Vector3>();
      foreach (string row in vertexData)
        vertices.Add(ParseVertex(row));
      return new FixedList<Vector3>(vertices);
    }

    private static Vector3 ParseVertex(string row)
    {
      try
      {
        string[] coords = Q.Words(row);
        return Q.v(
          float.Parse(coords[0], CultureInfo.InvariantCulture),
          float.Parse(coords[1], CultureInfo.InvariantCulture),
          float.Parse(coords[2], CultureInfo.InvariantCulture));
      }
      catch
      {
        throw new Exception("Could not parse this as a vertex: " + row);
      }
    }

    private static int ParseNumPolygons(string row)
    {
      if (!row.StartsWith("polygons "))
        throw new Exception("Expected polygons then an integer, found " + row);
      string[] words = Q.Words(row);
      return int.Parse(words[1]);
    }

    private static int ParseNumVertices(string row)
    {
      if (!row.StartsWith("vertices "))
        throw new Exception("Expected vertices then an integer, found " + row);
      string[] words = Q.Words(row);
      return int.Parse(words[1]);
    }

    static string ByteArrayToString(byte[] array)
    {
      return System.Text.ASCIIEncoding.ASCII.GetString(array);
    }

    public static ColoredPolygonMesh FromByteArray(byte[] array)
    {
      return FromString(ByteArrayToString(array));
    }
  }
}
